package com.qingzhuge.common.email;

import com.qingzhuge.common.Constants;
import com.qingzhuge.common.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.util.Date;
import java.util.Objects;
import java.util.Properties;

import static com.qingzhuge.common.Constants.DEFAULT_ENCODING;

/**
 * @author : zero.xiao
 * @description : 邮件引擎
 * @modified :
 */
public final class EmailSender {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * MIME邮件对象
     */
    private MimeMessage mimeMsg;
    /**
     * 邮件会话对象
     */
    private Session session;
    /**
     * 系统属性
     */
    private Properties props;
    /**
     * smtp认证用户名和密码
     */
    private String username = "";
    private String password = "";
    private String userkey = "";
    private boolean ssl;

    /**
     * Multipart对象,邮件内容,标题,附件等内容均添加到其中后再生成MimeMessage对象
     */
    private Multipart mp;

    /**
     * @param host  string 主机地址
     * @param port  string 端口
     * @param ssl boolean 是否开启ssl
     */
    public EmailSender(String host, String port, boolean ssl) {
        try {
            this.ssl = ssl;
            logger.info(Resources.getMessage(Constants.I18n.EMAIL_SET_HOST), host);
            if (props == null) {
                // 获得系统属性对象
                props = System.getProperties();
            }
            // 设置SMTP主机
            props.put("mail.smtp.host", Objects.requireNonNull(host));
            String mailSmtpPort = "mail.smtp.port";
            if (port == null || "".equals(port.trim())) {
                props.put(mailSmtpPort, Objects.requireNonNull(port));
            } else {
                props.put(mailSmtpPort, "25");
            }
            //gmail支持
            String smtpGmailcom = "smtp.gmail.com";
            if (smtpGmailcom.equals(host) || ssl) {
                props.put(mailSmtpPort, "465");
                String sslFactory = "javax.net.ssl.SSLSocketFactory";
                props.setProperty("mail.smtp.socketFactory.class", sslFactory);
                props.setProperty("mail.smtp.socketFactory.fallback", "false");
                props.setProperty("mail.smtp.socketFactory.port", "465");
            }
            if (!createMimeMessage()) {
                throw new RuntimeException("创建MIME邮件对象和会话失败");
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * @param name String
     * @param password String
     * @return boolean
     */
    public boolean setNamePass(String name, String password, String key) {
        this.username = name;
        this.password = password;
        this.userkey = key;
        setNeedAuth();
        return createMimeMessage();
    }

    /**
     *
     */
    private void setNeedAuth() {
        if (props == null) {
            props = System.getProperties();
        }
        String mailSmtpAuth = "mail.smtp.auth";
        //email.authorisation.code
        if (userkey == null || "".equals(userkey.trim())) {
            props.setProperty(mailSmtpAuth, "false");
            logger.info(Resources.getMessage(Constants.I18n.EMAIL_SET_AUTH), "false");
        } else {
            props.setProperty(mailSmtpAuth, "true");
            logger.info(Resources.getMessage(Constants.I18n.EMAIL_SET_AUTH), "true");
        }
    }

    /**
     * 创建MIME邮件对象
     *
     * @return boolean
     */
    private boolean createMimeMessage() {
        if (session == null) {
            try {
                // 获得邮件会话对象
                session = Session.getInstance(props, new Authenticator() {
                    @Override
                    protected PasswordAuthentication getPasswordAuthentication() {
                        if (userkey == null || "".equals(userkey.trim())) {
                            return null;
                        }
                        if (ssl) {
                            return new PasswordAuthentication(username, password);
                        }
                        return new PasswordAuthentication(username, userkey);
                    }
                });
            } catch (Exception e) {
                logger.error(Resources.getMessage(Constants.I18n.EMAIL_ERROR_TALK), e.getLocalizedMessage());
                return false;
            }
        }
        if (mimeMsg == null) {
            try {
                // 创建MIME邮件对象
                mimeMsg = new MimeMessage(session);
                mp = new MimeMultipart();
                return true;
            } catch (Exception e) {
                logger.error(Resources.getMessage(Constants.I18n.EMAIL_ERROR_MIME), e.getLocalizedMessage());
                return false;
            }
        } else {
            return true;
        }
    }

    /**
     * 设置主题
     *
     * @param mailSubject String
     * @return boolean
     */
    public boolean setSubject(String mailSubject) {
        logger.info(Resources.getMessage(Constants.I18n.EMAIL_SET_SUBJECT), mailSubject);
        try {
            mimeMsg.setSubject(mailSubject, DEFAULT_ENCODING);
            return true;
        } catch (Exception e) {
            logger.error(Resources.getMessage(Constants.I18n.EMAIL_ERROR_SUBJECT), e);
            return false;
        }
    }

    /**
     * 设置内容
     *
     * @param mailBody String
     */
    public boolean setBody(String mailBody) {
        try {
            BodyPart bp = new MimeBodyPart();
            bp.setContent("" + mailBody, "text/html;CHARSET=UTF-8");
            mp.addBodyPart(bp);
            return true;
        } catch (Exception e) {
            logger.error(Resources.getMessage(Constants.I18n.EMAIL_ERROR_BODY), e);
            return false;
        }
    }

    /**
     * 设置附件
     *
     * @param filename String
     * @return boolean
     */
    public boolean addFileAffix(String filename) {
        logger.info(Resources.getMessage(Constants.I18n.EMAIL_ADD_ATTEND), filename);
        try {
            BodyPart bp = new MimeBodyPart();
            FileDataSource fileds = new FileDataSource(filename);
            bp.setDataHandler(new DataHandler(fileds));
            bp.setFileName(MimeUtility.encodeText(fileds.getName()));
            mp.addBodyPart(bp);
            return true;
        } catch (Exception e) {
            logger.error(filename, e);
            return false;
        }
    }

    /**
     * 设置发信人
     *
     * @param from String
     * @return boolean
     */
    public boolean setFrom(String from) {
        try {
            String[] f = Objects.requireNonNull(from).split(",");
            if (f.length > 1) {
                from = MimeUtility.encodeText(f[0]) + "<" + f[1] + ">";
            }
            // 设置发信人
            mimeMsg.setFrom(new InternetAddress(from));
            return true;
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return false;
        }
    }

    /**
     * 设置收信人
     *
     * @param to String
     * @return boolean
     */
    public boolean setTo(String to) {
        if (to == null) {
            return false;
        }
        logger.info(Resources.getMessage(Constants.I18n.EMAIL_SET_TO), to);
        try {
            mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
            return true;
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return false;
        }
    }

    /**
     * 设置抄送人
     *
     * @param copyto String
     * @return boolean
     */
    public boolean setCopyTo(String copyto) {
        if (copyto == null) {
            return false;
        }
        logger.info(Resources.getMessage(Constants.I18n.EMAIL_SET_COPYTO), copyto);
        try {
            mimeMsg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(copyto));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 发送邮件
     */
    public boolean sendout() {
        try {
            mimeMsg.setContent(mp);
            // 设置发送日期
            mimeMsg.setSentDate(new Date());
            mimeMsg.saveChanges();

            logger.info(Resources.getMessage(Constants.I18n.EMAIL_SENDING));
            // 发送
            Transport.send(mimeMsg);
            logger.info(Resources.getMessage(Constants.I18n.EMAIL_SEND_SUCC));
            return true;
        } catch (Exception e) {
            logger.error(Resources.getMessage(Constants.I18n.EMAIL_SEND_ERR), e);
            return false;
        }
    }
}
